// data中的属性转换成get 和 set
class Observer {
  // 创建时则将属性转换为get 和 set
  constructor (data) {
    this.walk(data)
  }
  // 遍历对象的所有属性
  walk (data) {
    // 1. 判断data是否是对象
    if(!data || typeof data !== 'object') {
      return
    }
    // 2. 遍历data对象的所有属性 Object.keys() 将键值对的键（属性名）获取出来转换为数组
    Object.keys(data).forEach(key => {
      this.defineReactive(data, key, data[key])
    })
  }
  // 把属性转换为get和set  使用Object.defineProperty()
  defineReactive (obj, key, val) {
    let that = this
    // 负责收集依赖，并发送通知
    let dep = new Dep()
    // 如果val是对象，把val内部的属性转换成响应式数据
    this.walk(val)
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      // $data 使用了该get函数 发生了闭包 延长val的作用域
      get () {
        // 访问属性值时 收集依赖 
        // target属性在watcher类中添加 存在target则添加订阅者
        Dep.target && dep.addSub(Dep.target)
        // 此处不传入 obj[key]  原因：obj[key]访问自身的相应属性，会触发自身的get 函数  造成死循环
        return val
      },
      set (newValue) {
        if(newValue === val) {
          return
        }
        val = newValue
        // 如果新赋值的属性是对象 ，把其内部属性转换为响应式数据
        // 此处this指向data 因此需要变量存储obsrver的this
        that.walk(newValue)
        // 发送通知 更新视图
        dep.notify()
      }
    })
  }
}